#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QMetaEnum>//OnActionTriggter中字符串转枚举类型
#include<QFileDialog>//OnNewFile中获取当前的文件和保存路径
#include<QFile>//Qt中专门用来处理文件操作的类
#include<QMessageBox>//弹提示框；LoadFile,下载文件中如果文件打开失败，需要一个提示弹窗
#include<QTextStream>//文本流；LoadFile，下载文件中如果文件打开成功，就需要读文件，采用流操作
#include<QSaveFile>//Qt中专门提供了这个类用于保存文件
//————————
 #include <QFont>//用于字体的加粗倾斜等

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //连接信号与槽
    connect(ui->file_menu,&QMenu::triggered,this,&MainWindow::OnActionTriggter);
    connect(ui->edit_menu,&QMenu::triggered,this,&MainWindow::OnActionTriggter);
    connect(ui->form_menu,&QMenu::triggered,this,&MainWindow::OnActionTriggter);
    connect(ui->win_menu,&QMenu::triggered,this,&MainWindow::OnActionTriggter);
    connect(ui->help_menu,&QMenu::triggered,this,&MainWindow::OnActionTriggter);

}

MainWindow::~MainWindow()
{
    delete ui;
}

//槽函数的前提：头文件中要有public slots:... ...
void MainWindow::OnActionTriggter(QAction *act)//点击菜单之后要干什么？
{
    //1\很多个菜单项，不知道act点击的是哪一个，因此要为他们做一个标识
    //2\用枚举来做标识，给菜单项附上枚举值，点击时获取枚举值，判断该按钮存取的枚举值是多少，通过switch语句来匹配
    //3\到头文件中声明一个枚举

    //1、先包含一个头文件QMetaEnum
    //2、定义对象(获取对象)
    QMetaEnum me=QMetaEnum::fromType<ActKind::ActionKind>();//成员函数fromType(),其类型是ActKind里的ActionKind
    //3、定义一个bool类型的ok
    bool ok;
    //4、将菜单项上的文本转换成枚举--使用函数keyToValue，获取当前获取到的菜单文本text()，通过函数toStdString().c_str()转换成字符串
    int k = me.keyToValue(act->text().toStdString().c_str(),&ok);//把ok传进去，判断转换是否成功；接收其返回值
    /*转换失败，直接return*/
    if(!ok)
        return;



    /*转换成功，继续操作switch*/
    switch(static_cast<ActKind::ActionKind>(k)){//通过静态类型转换，将int转换成枚举类型;将k转换一下
    //转换完毕

    //(1)新建文件
    case ActKind::ActionKind::NewFile:
        //（1）先要定义一个参数：头文件--slots处:OnNewFile
        //（2）调用一下OnNewFile函数
        OnNewFile();
        break;
    //(2)打开文件
    case ActKind::ActionKind::OpenFile:
        OnOpenFile();
        break;
    //(3)保存文件
    case ActKind::ActionKind::SaveFile:
        OnSave();//（从MaybeSave()中弹窗是否要保存引出来的）此处也用到要保存文件，顺便调用该函数
        break;
    //(4)另存文件
    case ActKind::ActionKind::SaveAsFile:
        OnSaveAs();//（从OnSave()中如果当前文件没有路径需要另存为引出来的）此处也用到要另保存文件，顺便调用该函数
        break;
    //(7)退出系统
    case ActKind::ActionKind::Quit:
        QApplication::quit();//QApplication里有quit()函数可以推出程序
        break;

    //<1>撤销
    case ActKind::ActionKind::Undo:
        ui->textEdit->undo();//用ui->textEdit里的undo()
        break;
    //<2>剪切
    case ActKind::ActionKind::Cut:
        ui->textEdit->cut();
        break;
    //<3>复制
    case ActKind::ActionKind::Copy:
        ui->textEdit->copy();
        break;
    //<4>粘贴
    case ActKind::ActionKind::Paste:
        ui->textEdit->paste();
        break;
    //<5>全选
    case ActKind::ActionKind::SelectAll:
        ui->textEdit->selectAll();
        break;

    /*————————*/

    //(5)打印文件
    case ActKind::ActionKind::PrintFile:
        break;
    //(6)预览打印文件
    case ActKind::ActionKind::PreviewFile:
        break;

    //[font-1]加粗
    case ActKind::ActionKind::Bold:
        OnBold();
        break;
    //[font-2]倾斜
    case ActKind::ActionKind::Italic:
        break;
    //[font-3]下划线
    case ActKind::ActionKind::UnderLine:
        break;
    //[paragraph-1]左对齐
    case ActKind::ActionKind::LeftAlignment:
        break;
    //[paragraph-2]居中
    case ActKind::ActionKind::CenterAlignment:
        break;
    //[paragraph-3]右对齐
    case ActKind::ActionKind::RightAlignment:
        break;
    //[paragraph-4]两端对齐
    case ActKind::ActionKind::JustifiedAlignment:
        break;
    //[3-1]颜色
    case ActKind::ActionKind::Color:
        break;

    //【1-1】关闭当前文件
    case ActKind::ActionKind::Close:
        break;
    //【1-2】关闭所有窗口
    case ActKind::ActionKind::CloseAllWindows:
        break;
    //【2-1】平铺
    case ActKind::ActionKind::Tile:
        break;
    //【2-2】层叠
    case ActKind::ActionKind::Cascade:
        break;
    //【3-1】下一个
    case ActKind::ActionKind::Next:
        break;
    //【3-2】前一个
    case ActKind::ActionKind::Previous:
        break;

    //{1}关于
    case ActKind::ActionKind::About:
        break;
    //{2}关于Qt
    case ActKind::ActionKind::AboutQt:
        break;

    }
}

void MainWindow::OnNewFile()
{
    //这里考虑到，新建一个文件（未命名），点击“保存”触发的是“另存为”，因为是新建的文件，所以没有指定其保存的位置
    //因此需要判断这个文件有没有保存过：先去写MaybeSave()函数

    //1、先判断这个文件有没有保存
    if(MaybeSave())//如果不需要保存
    {
        //直接把原有的内容清空
        ui->textEdit->clear();
        //路径也置为空
        cur_file=QString();
        //手动将文本内容变成没有编辑
        ui->textEdit->document()->setModified(false);
    }
    //2、需要保存时，在判断时
}
//（一）打开文件（是否需要保存当前文件）
void MainWindow::OnOpenFile()
{
    //1、判断当前文件有没有保存
    //2、因此需要添加一个辅助函数，从头文件开始private:MaybeSave()
    if(MaybeSave())
    {
        //(1)如果需要保存，就需要获取一下当前的文件和保存路径，通过QFileDialog（#include）来
        //(2)定义一下对象，获取绝对路径;QFileDialog里面有一个静态成员getOpenFileName()
        QString fileName=QFileDialog::getOpenFileName(this);//传递一个父对象this;这样文件对话框就创立好了
        //(3)判断我们获取到的fileName不为空，就需要将文件的内容加载到文件夹里面
        if(!fileName.isEmpty())
            //要打开文件，去获取要打开的文件名，如果打开的文件名不为空，就将文件的内容加载到文件夹里面
            //如果不需要保存，点打开文件的时候，弹框，点了“取消”，那么什么都不用做
            //因此需要加载文件，先写一个辅助函数 ，从头文件开始
            //<1>直接调用
            LoadFile(fileName);
    }

    //运行后测试步骤：1、随意打一些数字，点击SaveFile保存一下,由于这是一个新建的文本，因此打开的是“另存为”，没问题
    //2、不动文本内容，点击OpenFile打开一下刚才保存的文件，结果发现弹窗提示“当前文件未保存”是否需要保存的情况
}
//（四）文件保存
bool MainWindow::OnSave()
{
    //保存这里考虑到，新建一个文件（未命名），点击“保存”触发的是“另存为”，因为是新建的文件，所以没有指定其保存的位置
    //因此需要判断这个文件有没有保存过
    //（1）添加一个QString到头文件的private里:QString cur_file;用于保存当前文件的路径位置
    if(cur_file.isEmpty())
        //如果当前位置为空，需要对它进行“另存为”的操作
        //因此也需要判断其“另存为”的操作有没有成功，所以到头文件中添加一个新的判断函数到slots:OnSaveAs()
        //1、如果为空，调用我们的OnSaveAs()
        return OnSaveAs();
    else//2、否则，当前文件在文件夹中已有路径，要将当前文件写入文件夹，需要一个保存函数，来一个辅助函数，从头文件开始private:中SaveFile()
        return SaveFile(cur_file);
}
//（四）-<1>另存为（即文件夹中没有路径的文件保存成功）
bool MainWindow::OnSaveAs()
{
    //1、需要获取你要保存的文件的一个路径位置，通过对话框，头文件（#include<QFileDialog>）
    QFileDialog dialog(this);
    //设定对话框的模式，将其设定成模态的，需要 选择 文件
    dialog.setWindowModality(Qt::WindowModal);
    dialog.setAcceptMode(QFileDialog::AcceptSave);//设置按钮
    //运行起来
    if(dialog.exec()!=QDialog::Accepted)//'不等于接受'说明接收了“取消”，说明当前文件不需要保存
        return false;
    //接受则需要保存
    return SaveFile(dialog.selectedFiles().first());//获取到先前选择的路径（.selectedFiles()），dialog.selectedFiles()返回的是一个列表，选取其第一条（.first()）
}

void MainWindow::OnBold()
{
    //1、获取文本编辑框里选中的内容
    //2、使用QFont将其加粗
    //3、加粗成功，返回true：提示加粗成功；反之False
    QFont fl=ui->textEdit->toPlainText();
    fl.setBold(true);
}



//（二）辅助函数MaybeSave()用于判断当前文件是否需要保存
bool MainWindow::MaybeSave()//MaybeSave()————（可能需要保存）
{
    //1、判断当前文本有没有修改:获取文本用document()，有没有修改用isModified()
    if(!ui->textEdit->document()->isModified())//（1-1）如果没有修改
        return true;//不保存
    //（1-2）有修改就弹框
        //<1-2-1>获取对象并增加三个按钮“保存”“不保存”“取消”；qApp->applicationName()--获取到当前应用程序的名称
    const QMessageBox::StandardButton btn=QMessageBox::warning(this,qApp->applicationName(),"文件没有保存",QMessageBox::Save|QMessageBox::Discard|QMessageBox::Cancel);
        //<1-2-2>通过switch语句判断点的是哪一个按钮
    switch (btn){
    case QMessageBox::Save://如果是保存，那么要先定义一个保存的函数，到头文件(slots:OnSave())
        return OnSave();
        break;
    case QMessageBox::Cancel://如果是取消，那么直接返回false
        return false;//不做任何操作
    }
    return true;//如果是不保存，那么直接返回true
}
//（三）加载文件（打开文件）--需要用到Qt里的文件操作：QFile类（#include）
void MainWindow::LoadFile(const QString &path)
{
    //1、定义完头文件之后（#include<QFile>）
    //2、定义类对象
    QFile file(path);//路径传进来
    //3、打开文件,file类里的open()函数打开，打开方式是只读,并且默认是文本形式打开,可能是乱码，所有前面要加一个非（!）
    if(!file.open(QFile::ReadOnly|QFile::Text)){
        //（1）如果打开失败，要给一个提示；用到#include<QMessageBox>--弹窗提示
        QMessageBox::warning(this,qApp->applicationName(),"无法打开文件");//qApp->applicationName()--获取到当前应用程序的名称
        return;
    }
    //（2）如果打开成功，就需要读文件，采用流操作，用到#include<QTextStream>--文本流
        //定义对象
    QTextStream in(&file);//把文件传进来
    //文件传进来之后，将它直接显示到我们界面上，在“设计”中得添加一个文本，随便一个垂直布局铺满
    //再。。。注意：以上设计完成后要先“构建”一下（即保存一下），才能继续
    ui->textEdit->setPlainText(in.readAll());//设置一下文本（setPlainText()），把文件里的数据读出来（in.readAll()），将它显示出来

    cur_file=path;//更新文件路径

    //（<——OpenFile——>）之所以会再一次弹窗提示是否要保存，是因为文本框被修改了，所以这里要设置一下，把文本框变成未修改
    ui->textEdit->document()->setModified(false);//用ui->textEdit里的setModified()

    //提示--用statusBar()
    statusBar()->showMessage("文件打开成功",2000);//显示时长2秒


    //在添加完ui->textEdit->document()->setModified(false);之后问题依然没有解决，还是弹窗说文件没有保存
    //那么看到SaveFile()函数，同样添加ui->textEdit->document()->setModified(false);
}
//（四）-<2>文件夹中已有路径的文件保存
bool MainWindow::SaveFile(const QString &path)
{
    //1、Qt中专门提供了这么一个类（#include<QSaveFile>）来保存文件
    //2、创建对象
    QSaveFile file(path);

    if(file.open(QFile::WriteOnly|QFile::Text))//打开文件
    {
        //（）打开成功：
        //3、写入
        QTextStream out(&file);//获取流对象，把file传进来
        //往流里面写入数据(把内容写入文件)
        out<<ui->textEdit->toPlainText();//ui->textEdit是文本，用toPlainText()来获取文本
        //4、file提交（.commit()）来判断是否保存成功
        if(!file.commit())
        {
            //（1）保存失败：提示框提示
            QMessageBox::warning(this,qApp->applicationName(),"文件保存失败！");
            return false;
        }
    }
    else//打开失败
        return false;
    //（2）保存成功：
    //5、更新文件路径
    cur_file=path;

    ui->textEdit->document()->setModified(false);

    //6、提示--用statusBar()
    statusBar()->showMessage("文件保存成功!",2000);//提示两秒钟
    return true;
}
